package com.bytedance.common.plugin.framework.update;

import android.content.Context;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public final class PluginUpdateDownloader {
    private String mPackageName;
    private Context mContext;
    private PluginDownloadListener mPluginDownloadListener;
    private DownloadStatus mDownloadStatus;

    public PluginUpdateDownloader(Context context, String packageName, PluginDownloadListener pluginDownloadListener) {
        this.mDownloadStatus = DownloadStatus.STATUS_PENDING;
        this.mContext = context;
        this.mPackageName = packageName;
        this.mPluginDownloadListener = pluginDownloadListener;
        this.onDownloadStatusChanged(DownloadStatus.STATUS_PENDING);
    }

    public final void onDownloadStatusChanged(DownloadStatus downloadStatus) {
        this.mDownloadStatus = downloadStatus;
        if (this.mPluginDownloadListener != null) {
            this.mPluginDownloadListener.onDownloadStatusChanged(this.mPackageName, this.mDownloadStatus);
        }
    }

    public final boolean execDownload(String downloadUrl, String outputFilePath, String desireEtag, int desireContentLength) {
        InputStream inputStream = null;
        int contentLength = -1;
        String etag = "";
        FileOutputStream fileOutputStream = null;
        byte[] buffer = new byte[4096];
        this.onDownloadStatusChanged(DownloadStatus.STATUS_RUNNING);
        int curBytes = 0;
        File outputFile = new File(outputFilePath);
        if (outputFile.exists()
                && !outputFile.isFile()
                && !outputFile.delete()) {
            return false;
        }
        boolean partial = false;
        if (desireEtag != null && desireEtag.length() != 0) {
            if (outputFile.exists()
                    && outputFile.isFile()
                    && System.currentTimeMillis() - outputFile.lastModified() < 24 * 60 * 60 * 1000L) {
                long length = outputFile.length();
                if (length < 52428800) {
                    partial = true;
                    curBytes = (int) length;
                }
            }
        } else if ((outputFile.exists()) && !outputFile.delete()) {
            return false;
        }

        if (curBytes == 0) {
            desireContentLength = -1;
        }
        int retry = 0;
        HttpURLConnection httpURLConnection = null;
        boolean shouldRetry = false;
        try {
            while (true) {
                if (retry >= 4) {
                    break;
                }

                try {
                    if (partial) {
                        fileOutputStream = new FileOutputStream(outputFile, true);
                        etag = desireEtag;
                    } else {
                        fileOutputStream = new FileOutputStream(outputFile);
                        etag = "";
                    }
                } catch (Exception e) {

                }

                httpURLConnection = (HttpURLConnection) new URL(downloadUrl).openConnection();
                httpURLConnection.setInstanceFollowRedirects(true);
                httpURLConnection.setConnectTimeout(6000);
                httpURLConnection.setReadTimeout(6000);
                retry++;
                if (curBytes > 0) {
                    if (etag != null && etag.length() > 0) {
                        httpURLConnection.addRequestProperty("If-Match", etag);
                    }
                    httpURLConnection.addRequestProperty("Range", "bytes=" + curBytes + "-");
                }

                int responseCode = httpURLConnection.getResponseCode();
                if (responseCode != 412) {
                    if (responseCode == 200 || responseCode == 206) {
                        if (curBytes == 0) {
                            etag = httpURLConnection.getHeaderField("Etag");
                            if (etag != null) {
                                String transferEncoding = httpURLConnection.getHeaderField("Transfer-Encoding");
                                String contentLengthValue = null;
                                if (transferEncoding == null) {
                                    contentLengthValue = httpURLConnection.getHeaderField("Content-Length");
                                    if (contentLengthValue != null) {
                                        contentLength = Integer.parseInt(contentLengthValue);
                                    } else {
                                        contentLength = desireContentLength;
                                    }
                                } else {
                                    contentLength = -1;
                                }

                                Log.d("PluginUpdateDownloader", "header content-length: " + contentLengthValue);
                                Log.d("PluginUpdateDownloader", "header Transfer-Encoding: " + transferEncoding);
                                Log.d("PluginUpdateDownloader", "header Etag: " + etag);
                                if (contentLengthValue == null
                                        && (transferEncoding == null || !transferEncoding.equalsIgnoreCase("chunked"))) {
                                    Log.w("PluginUpdateDownloader", "can not know content length, give up");
                                    break;
                                }

                                if (this.mPluginDownloadListener != null) {
                                    this.mPluginDownloadListener.onReceiveHeaderInfo(this.mPackageName, contentLength, etag);
                                }
                            }
                        }

                        inputStream = httpURLConnection.getInputStream();
                        int totalBytes = curBytes;
                        while (true) {
                            int read = inputStream.read(buffer);
                            if (read != -1) {
                                totalBytes += read;
                                fileOutputStream.write(buffer, 0, read);
                                if ((long) totalBytes <= 52428800L) {
                                    if (this.mPluginDownloadListener != null) {
                                        this.mPluginDownloadListener.onDownloadProgressChanged();
                                    }
                                    continue;
                                } else {
                                    shouldRetry = true;
                                    Log.w("PluginUpdateDownloader", "exceed max_apk_size: " + totalBytes);
                                    break;
                                }
                            }
                            if (contentLength > 0 && contentLength != totalBytes) {
                                Log.w("PluginUpdateDownloader", "content length mismatch");
                            }
                            httpURLConnection.disconnect();
                            return true;
                        }
                    } else {
                        Log.w("PluginUpdateDownloader", "download failed with code " + responseCode);
                        break;
                    }
                } else {
                    shouldRetry = true;
                }

                if (shouldRetry) {
                    curBytes = 0;
                    partial = false;
                    if (fileOutputStream != null) {
                        try {
                            fileOutputStream.close();
                            fileOutputStream = null;
                        } catch (Exception e) {

                        }
                    }

                    if (httpURLConnection != null) {
                        try {
                            httpURLConnection.disconnect();
                        } catch (Exception e) {

                        }
                    }

                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (Exception e) {

                        }
                    }
                    continue;
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (httpURLConnection != null) {
                try {
                    httpURLConnection.disconnect();
                } catch (Exception e) {

                }
            }

            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {

                }
            }

            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (Exception e) {

                }
            }
        }
        this.onDownloadStatusChanged(DownloadStatus.STATUS_FAILED);
        return false;
    }

}

